/**
 *    Copyright (C) 2009  Victor Smirnov <aist11@gmail.com>
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License along
 *    with this program; if not, write to the Free Software Foundation, Inc.,
 *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *    See LICENSE.exceptions in the root folder of this project for possible
 *    exceptions
 *
 */

#ifndef _CUBEFS_CORE_MODELS_TREE_MAP_MODEL_API_HPP
#define _CUBEFS_CORE_MODELS_TREE_MAP_MODEL_API_HPP

#include <cubefs/core/models/tree_map/names.hpp>
#include <cubefs/api/models/logs.hpp>

#define CUBEFS_SOURCE "cubefs/core/models/tree_map/model/api.hpp:" CUBEFS_AT

namespace cubefs    {
namespace ctr       {

CUBEFS_MODEL_PART_BEGIN(cubefs::models::tree_map::ApiName)

    typedef typename Base::Types                                                Types;
    typedef typename Base::PageMgr                                              PageMgr;

    typedef typename Base::Page                                                 Page;
    typedef typename Base::ID                                                   ID;


    typedef typename Base::NodeBase                                             NodeBase;
    typedef typename Base::Counters                                             Counters;
    typedef typename Base::Iterator                                             Iterator;

    typedef typename Base::NodeDispatcher                                       NodeDispatcher;
    typedef typename Base::RootDispatcher                                       RootDispatcher;
    typedef typename Base::LeafDispatcher                                       LeafDispatcher;
    typedef typename Base::NonLeafDispatcher                                    NonLeafDispatcher;

    typedef typename Base::Node2RootMap                                         Node2RootMap;
    typedef typename Base::Root2NodeMap                                         Root2NodeMap;

    typedef typename Base::NodeFactory                                          NodeFactory;

    typedef typename Base::Key                                                  Key;
    typedef typename Base::Value                                                Value;

    typedef typename Base::ApiKeyType                                           ApiKeyType;
    typedef typename Base::ApiValueType                                         ApiValueType;

    static const Int Indexes                                                    = Base::Indexes;

    BigInt KeyIndex(Key key, Int c) {
        Iterator i = me_.FindLE(key, c, false);
        if (!i.IsEof()) {
            NodeBase* page = i.page();
            BigInt keys = i.key_idx();

            while (!page->is_root()) {
                Int pidx = page->parent_idx();
                page = me_.GetParent(page);

                for (Int c = 0; c < pidx; c++) {
                    NodeBase* child = me_.GetChild(page, c);
                    keys += child->counters().key_count();
                }
            }

            return keys;
        }
        else {
            return -1;
        }
    }

    Iterator GetByIndex(BigInt index) {
        NodeBase *node = me_.GetRoot();
        if (node != NULL) {
            BigInt keys = 0;
            while (!node->is_leaf())
            {
                Int size = me_.GetChildrenCount(node);

                Int idx = -1;

                for (Int c = 0; c < size; c++) {
                    NodeBase* child = me_.GetChild(node, c);
                    BigInt count = child->counters().key_count();

                    if (index < keys + count) {
                        idx = c;
                        break;
                    }
                    else {
                        keys += count;
                    }
                }

                if (idx < 0) {
                    return Iterator(me_);
                }
                else {
                    node = me_.GetChild(node, idx);
                }
            }

            return Iterator(node, index - keys, me_);
        }
        else {
            return Iterator(me_);
        }
    }
    

CUBEFS_MODEL_PART_END

}
}

#undef CUBEFS_SOURCE

#endif
